package com.example.library_common.view.video_view;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.res.Configuration;
import android.net.Uri;
import android.os.Looper;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.annotation.Nullable;

import com.example.library_common.BuildConfig;
import com.example.library_common.R;
import com.example.library_common.glidmodule.GlideApp;
import com.example.library_common.global.AppGlobals;
import com.example.library_common.utils.QMUIDisplayHelper;
import com.example.library_common.view.video_view.utils.VideoViewUtils;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.DefaultLoadControl;
import com.google.android.exoplayer2.DefaultRenderersFactory;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.LoadControl;
import com.google.android.exoplayer2.PlaybackPreparer;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.ext.okhttp.OkHttpDataSourceFactory;
import com.google.android.exoplayer2.source.BehindLiveWindowException;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
import com.google.android.exoplayer2.source.dash.DashMediaSource;
import com.google.android.exoplayer2.source.hls.HlsManifest;
import com.google.android.exoplayer2.source.hls.HlsMediaSource;
import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist;
import com.google.android.exoplayer2.source.hls.playlist.HlsMediaPlaylist;
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.ui.DefaultTimeBar;
import com.google.android.exoplayer2.ui.PlayerControlView;
import com.google.android.exoplayer2.ui.PlayerView;
import com.google.android.exoplayer2.upstream.BandwidthMeter;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.upstream.DefaultAllocator;
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource;
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;
import com.google.android.exoplayer2.upstream.FileDataSourceFactory;
import com.google.android.exoplayer2.upstream.HttpDataSource;
import com.google.android.exoplayer2.upstream.ResolvingDataSource;
import com.google.android.exoplayer2.upstream.TransferListener;
import com.google.android.exoplayer2.upstream.cache.Cache;
import com.google.android.exoplayer2.upstream.cache.CacheDataSource;
import com.google.android.exoplayer2.upstream.cache.CacheDataSourceFactory;
import com.google.android.exoplayer2.upstream.cache.NoOpCacheEvictor;
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
import com.google.android.exoplayer2.util.EventLogger;

import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.concurrent.TimeUnit;

import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;

public class CustomVideoViewPlayer extends PlayerView implements Player.EventListener, View.OnClickListener, PlaybackPreparer {

    private ImageButton mVideoViewScreenBtn;

    private View mVideoViewTopController;

    private ImageView artworkView;

    private boolean initPlayer;

    //当前是否正在播放
    private boolean isCurrentPlaying;

    private SimpleExoPlayer exoPlayer;

    protected String userAgent = encodeHeadInfo(
            AppGlobals.getApplication().getResources().getString(R.string.recommend));

    private DefaultBandwidthMeter bandwidthMeter;

    private View exo_progress_zone;

    private PlayerControlView mController;

    private ViewTouchInterceptLayout onPlayingLayout;

    private DefaultTimeBar exo_progress;
//
//    private ViewTouchInterceptLayout onPlayingLayout;

    public CustomVideoViewPlayer(Context context) {
        this(context, null);
    }

    public CustomVideoViewPlayer(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    @SuppressLint("CustomViewStyleable")
    public CustomVideoViewPlayer(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);

        try {
            Class<? extends CustomVideoViewPlayer> aClass = getClass();
            Class<?> superclass = aClass.getSuperclass();
            if (superclass != null) {
                Field controllerField = superclass.getDeclaredField("controller");
                controllerField.setAccessible(true);
                mController = (PlayerControlView) controllerField.get(this);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }


        initPlayer(context);

        mVideoViewScreenBtn = findViewById(R.id.mVideoViewScreenBtn);
        mVideoViewTopController = findViewById(R.id.mVideoViewTopController);
        artworkView = findViewById(R.id.exo_artwork);
        onPlayingLayout = findViewById(R.id.onPlayingLayout);
        exo_progress = findViewById(R.id.exo_progress);
        if (mVideoViewScreenBtn != null) {
            mVideoViewScreenBtn.setSelected(QMUIDisplayHelper.isPortrait());
            mVideoViewScreenBtn.setOnClickListener(this);
        }

        exo_progress_zone = findViewById(R.id.exo_progress_zone);

    }


    private void initPlayer(Context context) {
        Context application = AppGlobals.getApplication();
//        int minBufferMs = 360000;
//        int maxBufferMs = 600000;
//        int bufferForPlaybackMs = 1000;
//        int bufferForPlaybackAfterReBufferMs = 5000;

        DefaultAllocator allocator =
                new DefaultAllocator(true, C.DEFAULT_BUFFER_SEGMENT_SIZE);

        LoadControl loadControl = new DefaultLoadControl.Builder()
                .setAllocator(allocator)
//                .setBufferDurationsMs(minBufferMs, maxBufferMs, bufferForPlaybackMs, bufferForPlaybackAfterReBufferMs)
                .setPrioritizeTimeOverSizeThresholds(true)
                .setTargetBufferBytes(C.LENGTH_UNSET)
                .createDefaultLoadControl();

        bandwidthMeter = new DefaultBandwidthMeter.Builder(context)
//                .setResetOnNetworkTypeChange(true)
                .build();
        TrackSelection.Factory trackSelection =
                new AdaptiveTrackSelection.Factory();

        DefaultTrackSelector.Parameters parameters = new DefaultTrackSelector
                .ParametersBuilder(context)
                .build();
        DefaultTrackSelector trackSelector = new DefaultTrackSelector(context, trackSelection);
        trackSelector.setParameters(parameters);

        DefaultRenderersFactory renderersFactory = new DefaultRenderersFactory(application);
        renderersFactory.setEnableDecoderFallback(true);
//        renderersFactory.setPlayClearSamplesWithoutKeys()
        renderersFactory.setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_PREFER);
        exoPlayer = new SimpleExoPlayer.Builder(application, renderersFactory)
                .setLoadControl(loadControl)
                .setLooper(Looper.getMainLooper())
                .setBandwidthMeter(bandwidthMeter)
//                .setUseLazyPreparation(true)
                .setTrackSelector(trackSelector)
                .build();
        if (BuildConfig.DEBUG) {
            exoPlayer.addAnalyticsListener(new EventLogger(trackSelector));
        }

        setPlayer(exoPlayer);
        setPlaybackPreparer(this);
    }


    @Override
    public void setPlayer(@Nullable Player player) {
        if (!initPlayer) {
            super.setPlayer(player);
            initPlayer = true;
        }

    }

    public View getVideoViewTopController() {
        return mVideoViewTopController;
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        Player player = getPlayer();
        if (player != null) {
            player.addListener(this);
        }
    }


    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        Player player = getPlayer();
        if (player != null) {
            player.removeListener(this);
        }
    }


    @Override
    public void onPause() {
        super.onPause();
        Player player = getPlayer();
        if (player != null) {

            isCurrentPlaying = player.isPlaying();

            player.setPlayWhenReady(false);
        }

    }

    public void onPlayingLayoutVisibly(boolean visible) {
        if (onPlayingLayout != null) {
//            int visibleInt = visible ? VISIBLE : GONE;
            onPlayingLayout.setIntercept(!visible);
            exo_progress.setEnabled(visible);
//            onPlayingLayout.setVisibility(visibleInt);
        }
    }

    public void setCover(String cover_url) {
        if (artworkView == null) {
            return;
        }
        GlideApp.with(this)
                .load(cover_url)
                .placeholder(R.mipmap.image_loading)
                .error(R.drawable.img_erros_bg_rect)
                .into(artworkView);
    }


    public long getVideoCurrentPosition() {

        return exoPlayer.getCurrentPosition();
    }


    public long getVideoDuration() {

        Player player = getPlayer();

        return player == null ? 0 : player.getDuration();
    }

    public void addVideoListener(Player.EventListener listener) {
        Player player = getPlayer();
        if (player != null) {
            player.addListener(listener);
        }
    }

    public void setProgressUpdateListener(@Nullable PlayerControlView.ProgressUpdateListener listener) {
        if (mController != null) {
            mController.setProgressUpdateListener(listener);
        }
    }

    @Override
    public void onResume() {
        super.onResume();

        if (!isCurrentPlaying) return;
        setCustomErrorMessage(null);
        Player player = getPlayer();


        if (player != null) {

            player.setPlayWhenReady(true);
        }
    }


    public void playUrlWithStart(String url) {
        setCustomErrorMessage(null);
        Player player = getPlayer();
        if (player instanceof SimpleExoPlayer) {
            ((SimpleExoPlayer) player).prepare(createMediaSource(url));
        }
        startVideo(url);

    }

    public void startVideo(String url) {
        onPlayingLayoutVisibly(true);
//        if (VideoViewUtils.isShowNetConfirm(url)) {
//
//            return;
//        }

        Player player = getPlayer();
        if (player != null) {
            player.setPlayWhenReady(true);
        }
    }


    @NotNull
    private MediaSource createMediaSource(String url) {
        Context mContext = AppGlobals.getApplication();
//        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
//        if (BuildConfig.DEBUG) {
//            interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
//        } else {
//            interceptor.setLevel(HttpLoggingInterceptor.Level.NONE);
//        }

        OkHttpClient build = new OkHttpClient.Builder()
                .connectTimeout(DefaultHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
                .readTimeout(DefaultHttpDataSource.DEFAULT_READ_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
//                .addNetworkInterceptor(interceptor)
                .retryOnConnectionFailure(true)
                .build();
        DataSource.Factory mHttpDataSourceFactory = new OkHttpDataSourceFactory(build, userAgent);
//        DataSource.Factory mHttpDataSourceFactory = new DefaultHttpDataSourceFactory(string);
        DefaultDataSourceFactory dataSourceFactory = new DefaultDataSourceFactory(
                mContext, bandwidthMeter, mHttpDataSourceFactory);

        MediaSource videoSource;
        if (url.contains(".m3u8")) {
            videoSource = new HlsMediaSource.Factory(dataSourceFactory)
                    .setAllowChunklessPreparation(true)
//                    .setUseSessionKeys(true)
                    .createMediaSource(Uri.parse(url));
//            setShowBuffering(SHOW_BUFFERING_NEVER);
//            if (exo_progress_zone != null) {
//                exo_progress_zone.setVisibility(INVISIBLE);
//            }

        } else {
            videoSource = new ProgressiveMediaSource.Factory(dataSourceFactory)
                    .createMediaSource(Uri.parse(url));

            if (exo_progress_zone != null) {
                exo_progress_zone.setVisibility(VISIBLE);
            }
        }
        return videoSource;
    }


    private String encodeHeadInfo(String headInfo) {
        StringBuilder stringBuffer = new StringBuilder();
        for (int i = 0, length = headInfo.length(); i < length; i++) {
            char c = headInfo.charAt(i);
            if (c <= '\u001f' || c >= '\u007f') {
                stringBuffer.append(String.format("\\u%04x", (int) c));
            } else {
                stringBuffer.append(c);
            }
        }
        return stringBuffer.toString();
    }

    @Override
    public void onPlayerError(ExoPlaybackException error) {
        if (isBehindLiveWindow(error)) {
            exoPlayer.retry();
        } else {
            String videoPlayError = AppGlobals.getApplication().getString(R.string.video_play_error);
            setCustomErrorMessage(videoPlayError);
        }

    }

    private boolean isBehindLiveWindow(ExoPlaybackException e) {
        if (e.type != ExoPlaybackException.TYPE_SOURCE) {
            return false;
        }
        Throwable cause = e.getSourceException();
        while (cause != null) {
            if (cause instanceof BehindLiveWindowException) {
                return true;
            }
            cause = cause.getCause();
        }
        return false;
    }

    @Override
    public void onClick(View view) {
        int id = view.getId();
        if (id == R.id.mVideoViewScreenBtn) {
            if (QMUIDisplayHelper.isLandscape()) {
                QMUIDisplayHelper.setPortrait((Activity) getContext());
            } else if (QMUIDisplayHelper.isPortrait()) {
                QMUIDisplayHelper.setLandscape((Activity) getContext());
            }
        }
    }

    @Override
    protected void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        if (mVideoViewScreenBtn != null) {
            mVideoViewScreenBtn.setSelected(QMUIDisplayHelper.isPortrait());
            mVideoViewScreenBtn.setOnClickListener(this);
        }
    }

    @Override
    public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
        if (playWhenReady && playbackState == Player.STATE_READY) {
            // media actually playing
            if (artworkView != null) {
                artworkView.setVisibility(GONE);
            }

        } else if (playWhenReady) {
            // might be idle (plays after prepare()),
            // buffering (plays when data available)
            // or ended (plays when seek away from end)
            if (artworkView != null) {
                artworkView.setVisibility(GONE);
            }
        } else {
            // player paused in any state
            if (artworkView != null) {
                artworkView.setVisibility(VISIBLE);
            }
        }
    }

    @Override
    public void onTimelineChanged(Timeline timeline, int reason) {
//        Object manifest = exoPlayer.getCurrentManifest();
//        if (manifest instanceof HlsManifest){
//            HlsManifest hlsManifest= (HlsManifest) manifest;
//            HlsMasterPlaylist masterPlaylist = hlsManifest.masterPlaylist;
//            HlsMediaPlaylist mediaPlaylist = hlsManifest.mediaPlaylist;
//        }
    }

    @Override
    public void preparePlayback() {
        setCustomErrorMessage(null);
        exoPlayer.retry();
    }

    public boolean isPlaying() {
        return exoPlayer.isPlaying();
    }
}
